package com;

import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

/**
 * ws连接信息
 * @ServerEndpoint 类层次注解, 将当前类定义为一个ws服务端
 * 注册值用于监听用户通过这个URL连接ws服务端
 **/
@ServerEndpoint("/websocket/{userId}")
@Component
public class ProductWebSocket {
    // (应该设计成线程安全)
    private static int onlineCount = 0;

    // concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
    // 若要实现服务端与单一客户端通信的话，可以使用Map来存放，其中Key可以为用户id
    private static ConcurrentHashMap<String, ProductWebSocket> webSocketSet =
            new ConcurrentHashMap<String, ProductWebSocket>();

    // 与某个客户端的连接会话, 来给客户端发送数据
    private Session session;

    // 当前发信息的人员编号
    private String userId = "";

    // 线程安全的统计在线人数
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        ProductWebSocket.onlineCount++ ;
    }

    public static synchronized void subOnlineCount() {
        ProductWebSocket.onlineCount-- ;
    }


    /**
     * 连接成功调用的方法
     * @param param 用户唯一标志
     * @param session [可选] 与的连接会话, 通过session来个客户端发送消息
     */
    @OnOpen
    public void onOpen(@PathParam(value = "userId") String param , Session session){
        // 接收到发消息人的人员编号
        userId = param;
        this.session = session;
        // 进入线程安全map中
        webSocketSet.put(param, this);
        // 在线人数加 1
        addOnlineCount();

        systemNotifyOnOpen(param, "用户id: " + param + " 加入连接! 当前在线人数: " + getOnlineCount());
        System.out.println("用户id: " + param + " 加入连接! 当前在线人数: " + getOnlineCount());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if (!"".equals(userId)) {
            // 根据用户id从 map中删除
            webSocketSet.remove(userId);
            // 在线人数减 1
            subOnlineCount();

            System.out.println("用户id: " + userId + " 关闭连接! 当前在线人数: " + getOnlineCount());
        }
    }

    /**
     * 收到客户端消息后调用的方法
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("来自客户端的消息: " + message);

        String sendUserId = message.split(",")[1];
        String sendMessage = message.split(",")[0];

        sendToUser(sendUserId, sendMessage);
    }

    /**
     * 给指定的人发送消息
     */
    public void sendToUser(String toSendUserId,String message) {
        try {
            if (webSocketSet.get(toSendUserId) != null) {
                webSocketSet.get(toSendUserId).sendMessage( "用户:" + userId + " : " + message);
            } else {
                if (webSocketSet.get(userId) != null){
                    webSocketSet.get(userId).sendMessage("用户: " + toSendUserId + " 已离线, 未收到您的消息");
                }

                System.out.println("消息接收人: " + toSendUserId + " 已经离线");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }


    }
    /**
     * 管理员发送消息t
     */
    public void systemSendToUser(String sendUserId, String message){
        try {
            if (webSocketSet.get(sendUserId) != null) {
                webSocketSet.get(sendUserId).sendMessage("系统消息: " + message);
            } else {
                System.out.println("用户: " + sendUserId + "已离线!");
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 登录时的系统通知
    public void systemNotifyOnOpen(String userId, String message) {
        try {

            for (String key : webSocketSet.keySet()) {
                if (!key.equals(userId)) {
                    // 给除当前有户外的其他用户发送通知
                    webSocketSet.get(key).sendMessage("系统消息>>>" + message);
                }
            }

            webSocketSet.get(userId).sendMessage("当前用户:<br>" + webSocketSet.keySet().toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 给所有人发送消息
     */
    public void sendAll(String message) {
        String sendMessage = message.split(",")[0];

        for (String key : webSocketSet.keySet()) {
            try {
                if (!userId.equals(key)) {
                    webSocketSet.get(key).sendMessage("用户: " + userId + " 发来消息(群发): " + message);
                    System.out.println("key = " + key);
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 发送消息
     */
    public void sendMessage(String message) throws IOException {
        // 同步发送
        this.session.getBasicRemote().sendText(message);
        // 异步发送
//        this.session.getAsyncRemote().sendText(message);

    }

    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("发生错误: " + error.getMessage());
        error.printStackTrace();
    }

}

